/**
 ****************************************************************************
 * Copyright (C) Marcelo F. Ochoa. All rights reserved.                      *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Apache Software License *
 * version 1.1, a copy of which has been included  with this distribution in *
 * the LICENSE file.                                                         *
 */

package com.prism.oracle;

import java.io.IOException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;

import com.prism.ConnInfo;
import com.prism.Content;
import com.prism.DBConnection;
import com.prism.SPProc;
import com.prism.toolkit.JowaArray;
import com.prism.toolkit.JowaImage;

/**
 * This class implements a ConcreteProduct class of Abstract Factory patterm.
 * Define a product object (DBConnJavaLite represent a connection to this DB)
 * to be created by the corresponding concrete factory. Implements the AbstractProduct Interface (DBConnection).
 * Also, implements a ConcreteClass of TemplateMethod patterm.
 * Implements the primitive operations to carry out subclass-specific steps of the algorithm (DBConnection::getGeneratedStream)
 */
public class DBConnJavaLite extends DBConnJava {
    Logger log = Logger.getLogger(DBConnJava8i.class);

    public DBConnJavaLite() {
      super();
    }

    /**
     * Create a concrete DBConnection (DBConnJava). Find extra properties attributes of this connection and return a
     * concrete connection object.
     */
    public DBConnection create(ConnInfo cc) {
        DBConnJavaLite con = new DBConnJavaLite();
        con.connInfo = cc;
        con.caseSensity = properties.getProperty("case","upper","DAD_"+cc.connAlias);
        if (log.isDebugEnabled())
          log.debug(".create - Package Case sensitivy set to: "+con.caseSensity);
        return con;
    }

    /**
     * Concrete operation of Template Method Pattern.
     * set the values of the JDBC execute method and execute it.
     */
    public void executeUpdate(CallableStatement cs, 
                                   Enumeration procArgListIterator,
                                   SPProc plp,
                                   HttpServletRequest req) 
        throws SQLException {
        int foundcount = 0;
        try {
          while (procArgListIterator.hasMoreElements()) {
            String name_args = (String)procArgListIterator.nextElement();
            String urlArgName = getCallerName(name_args, req.getParameterNames());
            String multi_vals[] = req.getParameterValues(urlArgName);
            String argumentType = plp.get(name_args.toLowerCase());
            if (argumentType == null) {
               log.warn("Argument '" + name_args + "' not in procedure description.");
               throw new SQLException("MANY PROCEDURES MATCH NAME, BUT NONE MATCHES SIGNATURE (parameter name '" +
                    name_args + "')");
            }
            //System.out.println("Adding argument "+name_args+" of type "+argumentType);
            if ("LONG RAW".equalsIgnoreCase(argumentType)) { // ARRAY variable
                if (urlArgName.indexOf(".") > 0) { // must be owa_image.point
                    // handle owa_image.point data type
                    JowaImage img = new JowaImage();
                    String val_x = req.getParameter(urlArgName.substring(0, urlArgName.indexOf(".")) + ".x");
                    String val_y = req.getParameter(urlArgName.substring(0, urlArgName.indexOf(".")) + ".y");
                    // the owa_image.point data type is a array of varchar index by binary integer
                    // Position 1 is args.x value
                    // Position 2 is args.y value
                    img.setX(new String(val_x.getBytes(connInfo.clientCharset)));
                    img.setY(new String(val_y.getBytes(connInfo.clientCharset)));
                    cs.setBytes(++foundcount, img.getBytes());
                    if (log.isDebugEnabled())
                      log.debug(".executeUpdate - '"+name_args+"' of type JowaImage passed with setBytes value="+img);
                } else {
                    JowaArray arr = new JowaArray(multi_vals.length);
                    for (int i = 0; i < multi_vals.length; i++) {
                        String s = new String(multi_vals[i].getBytes(connInfo.clientCharset), connInfo.dbCharset);
                        arr.setValueAt(i, s);
                    } // end for make array variable
                    cs.setBytes(++foundcount, arr.getBytes());
                    if (log.isDebugEnabled())
                      log.debug(".executeUpdate - '"+name_args+"' of type JowaArray passed with setBytes value="+arr);
                }
            } else { // otherwise, must be scalar type or cast to scalar
                String s;
                if (urlArgName.indexOf(".") > 0) {
                    s = new String(req.getParameter(req.getParameter(urlArgName.substring(0, urlArgName.indexOf(".")) +
                        ".x")).getBytes(connInfo.clientCharset), connInfo.dbCharset);
                    if (log.isDebugEnabled())
                      log.debug(".executeUpdate - Casting from owa_image.point to varchar2 '"+name_args+"' value="+s);
                } else if (multi_vals != null) {
                    s = new String(multi_vals[0].getBytes(connInfo.clientCharset));
                    if (log.isDebugEnabled())
                      log.debug(".executeUpdate - Casting from array to varchar2 '"+name_args+"' value="+s);
                } else {
                    s = new String(req.getParameter(urlArgName).getBytes(connInfo.clientCharset));
                }
                cs.setString(++foundcount, s);
                if (log.isDebugEnabled())
                  log.debug(".executeUpdate - '"+name_args+"' passed with setString value='"+s+"'");
            } // end scalar type or cast to scalar
          } // end while has arguments
          // Exec procedure in DB
          cs.executeUpdate();
        } catch (UnsupportedEncodingException ue) {
            if (log.isDebugEnabled())
              log.debug(".executeUpdate - Java Lite Adapter - Error Decoding arguments values",ue);
            throw new SQLException("Java Lite Adapter - Error Decoding arguments values:\n" + ue.getMessage());
        }
    }

    /** 
     * Concrete operation of Template Method pattern. 
     * Return generated page as StringReader 
     **/
    public Content getGeneratedStream(HttpServletRequest req) throws IOException, SQLException, UnsupportedEncodingException {
        Content generatedContent = new Content();
        CallableStatement cs = null;
        cs = sqlconn.prepareCall("{ call JxtpBuff.flush() }");
        cs.execute();
        cs.close();
        PreparedStatement pstmt = sqlconn.prepareStatement("SELECT JxtpBuff.GETPAGE() FROM DUAL");
        ResultSet rs = pstmt.executeQuery();
        rs.next();
        byte[] ba = rs.getBytes(1);
        if (log.isDebugEnabled())
          log.debug(".getGeneratedStream - Page=>\n"+new String(ba,connInfo.dbCharset));
        generatedContent.setPage(new StringReader(new String(ba)));
        return generatedContent;
    }
}
